package pt.iscte.pcd.project.local;

import java.util.Iterator;
import java.util.LinkedList;

import pt.iscte.pcd.project.exceptions.FileSystemException;
import pt.iscte.pcd.project.interfaces.EntryType;
import pt.iscte.pcd.project.interfaces.PCDDirectory;
import pt.iscte.pcd.project.interfaces.PCDEntry;
import pt.iscte.pcd.project.interfaces.PCDFile;

public class LocalDirectory extends LocalEntry implements PCDDirectory {
	private LinkedList<LocalEntry> listFiles = new LinkedList<LocalEntry>();
	private boolean lock = false;

	public LocalDirectory(String nome, PCDDirectory parent) {
		super(nome, EntryType.DIRECTORY, parent);

	}

	/**
	 * verifies if an entry exists given a string name
	 * @return boolean
	 * @param String name
	 */
	@Override
	public boolean entryExists(String name) {
		try {
			String[] listFiles = getDirectoryListing();
			for (String string : listFiles) {
				if(string.equals(name)) return true;
			}
		} catch (FileSystemException e) {
			e.printStackTrace();
		}
		return false;
	}

	/**
	 * Create a new file given an string name
	 * @return PCDFile
	 * @param String name
	 * @throws FileSystemException
	 */


	@Override
	public PCDFile newFile(String name) throws FileSystemException {
		LocalFile file = new LocalFile(name, this);
		getListFiles().add(file);
		return file;
	}

	/**
	 * Creates a new directory given a String name 
	 * @return PCDDirectory
	 * @param String name
	 * @throws FileSystemException
	 */

	@Override
	public PCDDirectory newDirectory(String name) throws FileSystemException {
		LocalDirectory directory = new LocalDirectory(name, this);
		getListFiles().add(directory);
		return directory;
	}

	/**
	 * Deletes an entry 
	 * @param PCDEntry
	 * @throws FileSystemException
	 */

	@Override
	public void delete(PCDEntry entry) throws FileSystemException {
		removeFilesInside(entry);
		Iterator<LocalEntry> it = getListFiles().iterator();
		while(it.hasNext()){
			LocalEntry itNext = it.next();
			if(itNext.equals(entry)) {
				it.remove();
				getFile().delete();
			}

		}

	}
	/**
	 * Auxiliary function for delete that analyze if is a Directory or a file inside a paste
	 * @param PCDEnty entry
	 */
	private void removeFilesInside(PCDEntry entry) {
		LocalEntry entryConverted = ((LocalEntry) entry);
		switch (entryConverted.getType()) {
		case DIRECTORY:
			deleteFilesInsidePaste((LocalDirectory)entry);
			entryConverted.getFile().delete();
			break;
		case FILE:
			entryConverted.getFile().delete();
		default:
			break;
		}
	}
	/**
	 * 	Auxiliary function for delete that analyze if is a Directory or a file inside a paste	
	 * @param entry
	 */
	private void deleteFilesInsidePaste(LocalDirectory entry) {
		Iterator<LocalEntry> it = entry.getListFiles().iterator();
		while(it.hasNext()){
			LocalEntry itNext = it.next();
			switch (itNext.getType()) {
			case DIRECTORY:
				deleteFilesInsidePaste((LocalDirectory)itNext);
				itNext.getFile().delete();
				it.remove();
				break;
			case FILE:
				itNext.getFile().delete();
				it.remove();
			default:
				break;
			}
		}
	}




	/**
	 * return an array of Strings with the names of the files/directories that are inside 
	 * @return String []
	 * @throws FileSystemException
	 */


	@Override
	public String[] getDirectoryListing() throws FileSystemException {
		String[] finalVector = new String[getListFiles().size()];
		for (int i = 0; i < finalVector.length; i++) {
			finalVector[i] = getListFiles().get(i).getName();
		}
		return finalVector;
	}

	/**
	 * return an entry given an name
	 * @return PCDEntry
	 * @param String name 
	 */

	@Override
	public PCDEntry getEntry(String name) {
		for (PCDEntry list : getListFiles()) {
			if(list.getName().equals(name))
				return list;
		}
		return null;
	}

	public LinkedList<LocalEntry> getListFiles() {
		return listFiles;
	}

	public void setListFiles(LinkedList<LocalEntry> listFiles) {
		this.listFiles = listFiles;
	}

	/**
	 * return the size of a directory
	 * @return int
	 */
	public int lengthPaste(){
		try {
			return countInsidePaste(this);
		} catch (FileSystemException e) {
			e.printStackTrace();
		}
		return -1;
	}

	/**
	 * Recursive function that receives a directory and recursively counts the length of all files (directories and files)
	 * @param directory
	 * @return
	 * @throws FileSystemException
	 */
	private int countInsidePaste(LocalDirectory directory) throws FileSystemException {
		int counter = 0;
		for (PCDEntry listFiles : directory.getListFiles()) {
			switch (listFiles.getType()) {
			case FILE:
				counter += ((LocalFile) listFiles).length();
				break;
			case DIRECTORY:
				counter += countInsidePaste((LocalDirectory) listFiles);
				break;
			default:
				throw new FileSystemException(0, "TYPE DOES NOT EXIST");
			}
		}
		return counter;
	}
	/**
	 * Create a new directory
	 */

	@Override
	public void createNew() {
		super.getFile().mkdir();
	}

	/**
	 * not used
	 */
	@Override
	public synchronized boolean readLock() {
		return false;
	}
	/**
	 * not used
	 */
	@Override
	public synchronized boolean writeLock() {
		return isLock();
	}
	/**
	 * not used
	 */

	@Override
	public void readUnlock() {
		// TODO Auto-generated method stub
	}
	/**
	 * not used
	 */
	@Override
	public synchronized void writeUnlock() {
		setLock(false);

	}

	public boolean isLock() {
		return lock;
	}

	public void setLock(boolean lock) {
		this.lock = lock;
	}

}
